Popular Searches
Popular Course Categories
Popular Courses

Forwarding Refs

Forwarding Refs

Advanced React Patterns and Features

Forwarding Refs in React JS

Forwarding Refs is a React technique that allows a parent component to pass a reference (ref) through a child component to a DOM element or another component. It is useful when a parent needs to perform imperative actions, such as focusing an input field, selecting text, scrolling to an element, or controlling a media element.

React JS Training: JustAcademy React JS Training Course

Course Demo: Register for React JS Course Demo


1. Learning Objectives

After completing this topic, you will be able to:

  • Understand refs and ref forwarding in React.
  • Learn how useRef() and forwardRef() work.
  • Pass refs from parent components to child components.
  • Access DOM elements from parent components.
  • Build reusable input and form components that support refs.
  • Understand the difference between React 18 and React 19 ref handling.
  • Use refs safely and follow React best practices.

2. What Is a Ref in React?

A ref is an object that allows a component to retain a reference to a DOM element or another value between renders. A ref created with useRef() contains a current property that can hold the referenced value.

Refs are commonly used when you need to interact directly with a DOM element instead of describing the behavior through React state and props.

Syntax

import { useRef } from "react";

const inputRef = useRef(null);

Initially, inputRef.current is null. After React attaches the ref to a DOM element, it contains that element.

Example: Focusing an Input

import { useRef } from "react";

export default function App() {
  const inputRef = useRef(null);

  function focusInput() {
    inputRef.current?.focus();
  }

  return (
    <div>
      <input ref={inputRef} placeholder="Enter your name" />
      <button type="button" onClick={focusInput}>
        Focus Input
      </button>
    </div>
  );
}

Explanation:

  1. useRef(null) creates a ref object.
  2. The ref attribute connects the object to the input element.
  3. When the button is clicked, focusInput() runs.
  4. The input receives focus through inputRef.current.focus().

3. What Is Forwarding Refs?

Forwarding refs means passing a ref received by a component to an element or another component inside it. This allows the parent component to access a particular element inside a reusable child component.

For example, a reusable CustomInput component may contain an HTML input. Ref forwarding lets the parent access that input without exposing the entire internal component structure.

Why Is Ref Forwarding Needed?

  • To focus an input inside a custom component.
  • To select text programmatically.
  • To scroll to a particular DOM element.
  • To control certain browser APIs or media elements.
  • To build reusable form controls and component libraries.
  • To expose a carefully limited set of imperative methods.

Important React Version Note

React 18 and earlier: Function components generally use forwardRef() to receive a ref from a parent.

React 19 and later: Function components can receive ref directly as a prop, so forwardRef() is no longer necessary for new function components. React documents forwardRef() as deprecated for future use, but existing code can still use it.

Reference: Official React forwardRef Documentation.


4. Understanding forwardRef()

The forwardRef() API wraps a render function so that a function component can receive the ref passed by its parent as a second argument.

Syntax

import { forwardRef } from "react";

const CustomInput = forwardRef(function CustomInput(props, ref) {
  return <input {...props} ref={ref} />;
});

export default CustomInput;

Parameters

Parameter Description
props Contains the properties passed from the parent component.
ref The ref received from the parent component.
forwardRef() Creates a component that can receive and forward a ref in React 18 and earlier.

How It Works

  1. The parent creates a ref using useRef().
  2. The parent passes the ref to the child component.
  3. The child receives the ref through forwardRef().
  4. The child attaches the ref to an internal DOM element.
  5. The parent can access that DOM element through ref.current.

Flow Diagram

Parent Component
       |
       | Creates useRef()
       v
Passes ref to Child Component
       |
       v
Child Receives ref Using forwardRef()
       |
       v
Attaches ref to DOM Element
       |
       v
Parent Accesses DOM Element

5. Example: Forwarding a Ref to an Input

This example uses the React 18-compatible forwardRef() pattern.

CustomInput.jsx

import { forwardRef } from "react";

const CustomInput = forwardRef(function CustomInput(props, ref) {
  return (
    <input
      {...props}
      ref={ref}
      className="custom-input"
    />
  );
});

export default CustomInput;

App.jsx

import { useRef } from "react";
import CustomInput from "./CustomInput";

export default function App() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current?.focus();
  }

  function handleClear() {
    if (inputRef.current) {
      inputRef.current.value = "";
      inputRef.current.focus();
    }
  }

  return (
    <div>
      <h2>Forwarding Refs Example</h2>
      <CustomInput
        ref={inputRef}
        type="text"
        placeholder="Enter your name"
      />
      <button type="button" onClick={handleFocus}>
        Focus Input
      </button>
      <button type="button" onClick={handleClear}>
        Clear Input
      </button>
    </div>
  );
}

Explanation

  • CustomInput is a reusable input component.
  • The parent passes inputRef to CustomInput.
  • forwardRef() receives the ref and attaches it to the actual input element.
  • The parent can call focus() or access the input value through inputRef.current.

Note: Directly changing an input's value is appropriate for this simple uncontrolled-input demonstration. For a controlled input, update its React state instead of changing the DOM value directly.


6. Forwarding Refs Through Multiple Components

Sometimes a ref must pass through more than one component before reaching the target DOM element. Each intermediate component must forward the ref in React 18 and earlier.

Example: App.jsx

import { useRef } from "react";
import FormField from "./FormField";

export default function App() {
  const inputRef = useRef(null);

  return (
    <div>
      <FormField
        ref={inputRef}
        label="Email Address"
        placeholder="Enter your email"
      />
      <button
        type="button"
        onClick={() => inputRef.current?.focus()}
      >
        Focus Email Field
      </button>
    </div>
  );
}

FormField.jsx

import { forwardRef } from "react";

const FormField = forwardRef(function FormField(props, ref) {
  const { label, ...inputProps } = props;

  return (
    <label>
      {label}
      <input {...inputProps} ref={ref} />
    </label>
  );
});

export default FormField;

The parent passes the ref to FormField, and FormField forwards it to the input. The parent can then focus the input directly.


7. Forwarding Refs in React 19

React 19 allows function components to receive ref directly as a prop. This makes ref forwarding simpler because a new function component does not need to be wrapped in forwardRef().

CustomInput.jsx

function CustomInput({ ref, ...props }) {
  return <input {...props} ref={ref} />;
}

export default CustomInput;

App.jsx

import { useRef } from "react";
import CustomInput from "./CustomInput";

export default function App() {
  const inputRef = useRef(null);

  return (
    <div>
      <CustomInput
        ref={inputRef}
        placeholder="Enter your name"
      />
      <button
        type="button"
        onClick={() => inputRef.current?.focus()}
      >
        Focus Input
      </button>
    </div>
  );
}

Important: The direct ref prop approach for function components requires React 19 or later. If your project uses React 18 or earlier, use forwardRef().

React 18 vs React 19

Feature React 18 and Earlier React 19 and Later
Receiving ref in a function component Use forwardRef(). Receive ref as a prop.
Passing ref to a DOM element Attach the forwarded ref. Attach the ref prop directly.
Existing forwardRef code Supported. Still supported, but no longer necessary for new function components.
Recommended approach for new function components forwardRef(). Direct ref prop.

8. Using forwardRef with useImperativeHandle

The useImperativeHandle() Hook lets a component control which methods or values a parent can access through a ref. Instead of exposing the entire DOM element, a component can expose only a small, specific API.

Example: Exposing Focus and Clear Methods

import {
  forwardRef,
  useImperativeHandle,
  useRef
} from "react";

const CustomInput = forwardRef(function CustomInput(props, ref) {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focus() {
      inputRef.current?.focus();
    },
    clear() {
      if (inputRef.current) {
        inputRef.current.value = "";
      }
    }
  }), []);

  return <input {...props} ref={inputRef} />;
});

export default CustomInput;

Parent Component

import { useRef } from "react";
import CustomInput from "./CustomInput";

export default function App() {
  const customInputRef = useRef(null);

  return (
    <div>
      <CustomInput
        ref={customInputRef}
        placeholder="Enter text"
      />
      <button
        type="button"
        onClick={() => customInputRef.current?.focus()}
      >
        Focus
      </button>
      <button
        type="button"
        onClick={() => customInputRef.current?.clear()}
      >
        Clear
      </button>
    </div>
  );
}

In this example, the parent receives an object with only two methods: focus() and clear(). It cannot directly access the internal input DOM node through this ref.

React 19 note: You can also use useImperativeHandle() with a ref received directly as a prop, without wrapping the component in forwardRef().


9. Common Use Cases of Ref Forwarding

Use Case Example
Input focus Focus a search box when a page loads or a button is clicked.
Text selection Select the text inside an input or textarea.
Scrolling Scroll to a particular section of a page.
Media control Call browser methods on a video or audio element.
Reusable components Allow a parent to focus an input inside a custom form control.
Imperative APIs Expose a limited set of methods through useImperativeHandle().

10. Refs vs Props vs State

Feature Refs Props State
Purpose Access DOM elements or store values between renders. Pass information from parent to child. Store data that affects the rendered UI.
Triggers re-render when changed No, changing ref.current alone does not. New prop values can trigger rendering. State updates schedule a render.
Mutability ref.current is mutable. Read-only from the receiving component's perspective. Updated using state setters or a reducer.
Typical example Focus an input. Pass a label or placeholder. Track a selected tab or form value.

11. Best Practices for Ref Forwarding

  • Use refs for imperative tasks that cannot be expressed naturally through props.
  • Prefer props and state for normal UI behavior, such as opening a modal or changing a selected tab.
  • Forward a ref to the intended DOM element or component; otherwise, the parent's ref may remain null.
  • Use optional chaining, such as inputRef.current?.focus(), when the element may not be mounted.
  • Avoid exposing internal DOM elements unnecessarily from high-level application components.
  • Use useImperativeHandle() when you need to expose a small, controlled set of methods.
  • Keep rendering logic pure and do not perform DOM operations during render.
  • Choose the ref syntax that matches your project's React version.
  • Remember that conditional rendering may mean the referenced element does not currently exist.

12. Common Mistakes and Solutions

Mistake Why It Happens Solution
Ref is always null The ref was not attached to a DOM element or forwarded correctly. Pass the ref through the child and attach it to the target.
Using forwardRef incorrectly in React 18 The ref is not received as an ordinary prop by a function component. Use forwardRef() and accept the ref as the second argument.
Using direct ref props in React 18 React 18 function components cannot receive refs as regular props in the React 19 manner. Use the React 18-compatible forwardRef() pattern.
Expecting a ref update to re-render the component Changing ref.current does not trigger a render. Use state if the changed value must update the UI.
Exposing too much of the DOM The parent becomes tightly coupled to child internals. Expose a limited API with useImperativeHandle() when appropriate.
Using refs for normal UI state UI changes are stored outside React state. Use useState() or useReducer() for values that determine rendered output.

13. Practical Project: Reusable Form with Forwarded Refs

Project Goal: Build a form with reusable input components that can be focused programmatically.

Requirements

  • Create a reusable custom input component.
  • Forward refs from the parent to the input elements.
  • Focus the name field when the user clicks a button.
  • Focus the email field when another button is clicked.
  • Validate the form using normal React state or browser form validation.

Suggested Folder Structure

src/
  App.jsx
  CustomInput.jsx
  styles.css

Expected Learning Outcome

You will understand how refs pass through reusable components and how parents can interact with selected DOM elements without making every input implementation part of the parent component.


14. Interview Questions and Answers

Q1. What is ref forwarding in React?

Ref forwarding allows a component to pass a ref it receives to a DOM element or another component inside it.

Q2. Why is forwardRef used?

In React 18 and earlier, forwardRef() allows a function component to receive a ref from its parent and attach it to an internal DOM element.

Q3. What is useRef?

useRef() is a React Hook that creates a persistent ref object with a mutable current property.

Q4. Does changing ref.current trigger a re-render?

No. Updating ref.current alone does not trigger a re-render.

Q5. Can a ref access a DOM element inside a child component?

Yes. The child must expose or forward the ref to that element, using the appropriate approach for the React version.

Q6. What is useImperativeHandle?

useImperativeHandle() lets a component customize the methods or values exposed through a ref.

Q7. Is forwardRef required in React 19?

No. React 19 function components can receive ref as a prop. The existing forwardRef() API remains supported, although it is no longer necessary for new function components.

Q8. What is the difference between refs and state?

Refs store values or DOM references without triggering renders when changed. State stores data that affects the UI and triggers rendering when updated.

Q9. What happens if a ref is not attached to any element?

The ref's current value will typically remain null, or become null when its element is removed.

Q10. Should refs be used for all DOM operations?

No. Use refs when imperative access is necessary, such as focusing, scrolling, selecting text, or controlling media. Prefer declarative props and state for ordinary UI behavior.


15. Practice Exercises

  1. Create a custom input component using forwardRef().
  2. Build a parent component that focuses the child input on a button click.
  3. Create a reusable textarea component that supports text selection.
  4. Forward a ref through two component layers to reach an input element.
  5. Use useImperativeHandle() to expose only focus() and clear() methods.
  6. Rewrite a simple example using React 19's direct ref prop.
  7. Compare the React 18 and React 19 implementations and identify the version-specific differences.

16. Quick Revision

  • A ref provides access to a DOM node or a persistent mutable value.
  • useRef() creates a ref object in function components.
  • forwardRef() allows function components to receive and forward refs in React 18 and earlier.
  • React 19 supports receiving ref directly as a prop in function components.
  • Refs are useful for focus, scrolling, text selection, and other imperative operations.
  • useImperativeHandle() can limit the API exposed through a ref.
  • Updating ref.current does not trigger a re-render.
  • Use state and props for ordinary declarative UI behavior.

17. Official React Documentation


18. React JS Training Resources

Explore more React JS concepts, Hooks, component design, and practical development through these course resources:

Conclusion

Ref forwarding helps reusable React components expose specific DOM elements or imperative methods to their parent components. Understanding useRef(), forwardRef(), and useImperativeHandle() makes it easier to build flexible form controls and reusable UI components. For modern React development, remember that React 19 supports passing refs directly as props to function components, while forwardRef() remains relevant to existing projects and compatibility with older React versions.

whatsapp